﻿using System;
using System.Collections.Generic;
using System.Linq;
using Warehouse.DataModel;

namespace Warehouse
{

    public static class RepositoryExtensions
    {
        static IList<decimal> LitrSizes = new[] { 32M, 33M, 33.8M, 33.83M, 34M, 33M, 35M };

        public static bool IsLitrSize(this Product @this)
        {
            switch (@this.Unit.Name.ToLower())
            {
                case "gallon": return true;
                case "oz":
                    var size = decimal.Parse(@this.SizeOrColor);
                    return LitrSizes.Contains(size);
                default: return false;
            }
        }

        public static string Title(this Product product)
        {
            return string.Format("{0}, {1}, {2}", product.ProductName.Name, product.SizeOrColor, product.Unit.Name);
        }

        public static bool IsRegularSize(this Product @this) { return !@this.IsLitrSize(); }

        public static Tuple<decimal, decimal> ClientCommission(this Brand brand, int clientId)
        {
            return brand.ClientBrandCommissions
                .Where(_ => _.ClientId == clientId)
                .AsEnumerable()
                .Select(_ => Tuple.Create(_.RegularProducts, _.LitrSizeProducts))
                .DefaultIfEmpty(Tuple.Create(brand.ClientDefaultRegularProductCommission, brand.ClientDefaultLitrSizeProductCommission))
                .First();
        }

        public static decimal DefaultBrandCommissionForClient(this Product product)
        {
            var brand = product.ProductName.Brand;
            return product.IsLitrSize() ? brand.ClientDefaultLitrSizeProductCommission: brand.ClientDefaultRegularProductCommission;
        }

        public static decimal ClientCommission(this Product product, int clientId)
        {
            var productCommission =
                from _ in product.ClientProductCommissions
                where _.ClientId == clientId
                select _.Value;

            var brandCommission =
                from _ in product.ProductName.Brand.ClientBrandCommissions
                where _.ClientId == clientId
                select product.IsLitrSize() ? _.LitrSizeProducts : _.RegularProducts;

            return 
                productCommission.Concat(brandCommission)
                .DefaultIfEmpty(product.DefaultBrandCommissionForClient())
                .First();
        }

        public static decimal DefaultBrandCommissionForVendor(this Product product)
        {
            var brand = product.ProductName.Brand;
            return product.IsLitrSize() ? brand.VendorDefaultLitrSizeProductCommission: brand.VendorDefaultRegularProductCommission;
        }

        public static decimal VendorCommission(this Product product, int vendorId)
        {
            var productCommission =
                from _ in product.VendorProductCommissions
                where _.VendorId == vendorId
                select _.Value;

            var brandCommission =
                from _ in product.ProductName.Brand.VendorBrandCommissions
                where _.VendorId == vendorId
                select product.IsLitrSize() ? _.LitrSizeProducts : _.RegularProducts;

            return
                productCommission.Concat(brandCommission)
                .DefaultIfEmpty(product.DefaultBrandCommissionForVendor())
                .First();
        }



        public static IEnumerable<Product> Products(this Brand brand)
        {
            return
                from pn in brand.ProductNames
                from p in pn.Products
                select p;

        }

        public static bool IsOldPackage(this UPC upc)
        {
            return upc.UpcNote.Code.ToUpper() == "OP";
        }

        public static bool Is(this Unit @this, string name)
        {
            if (@this == null) return false;
            return @this.Name.ToLower() == name;
        }
        public static bool IsOz(this Unit @this) { return @this.Is("oz"); }
        public static bool IsGallon(this Unit @this) { return @this.Is("gallon"); }
        public static bool IsSizeOrColorRequired(this Unit @this)
        {
            return new[] { "oz", "color", "gram" }.Any(@this.Name.Equals);
        }

        public static decimal TotalPurchases(this Vendor vendor)
        {
            return
            (
                from po in vendor.PurchaseOrders
                from li in po.PurchaseOrderLineItems
                select li.BasePrice * (1M + li.Commission / 100M) * li.Quantity
            ).Sum();
        }

        public static decimal TotalSales(this Client client)
        {
            return
            (
                from invoice in client.Invoices
                from li in invoice.InvoiceLineItems
                select li.BasePrice * (1M + li.Commission / 100M) * li.Quantity
            ).Sum();
        }

        public static bool IsNotLushEssence(this Client @this) 
        {
            return @this.CompanyName != "Lush Essence";
        }
    }
}